﻿using System;
using System.Linq;
using Missbot.Core.Base;
using Missbot.Core.Cache;
using Missbot.Core.SyntaxChecker.ParamCheckers;
using Dolany.UtilityTool;
using JetBrains.Annotations;
using Missbot.AIModule.Base;

namespace Missbot.AIModule.Record
{
    [UsedImplicitly]
    public class CharactorSettingMod : IAIModule
    {
        public override string Name => "人物设定";

        private const int MaxCharNumPerUser = 10;
        private const int MaxSettingPerChar = 7;

        [ModuleEnter(Command = "人物设定", Description = "设定一个人物", SyntaxHint = "[人物名] [设定项] [设定内容]", ChannelType = ChannelType.Messaging)]
        public bool SetCharactor(InboxSession session, string charactor, string settingName, UnlimitedStr contentParam)
        {
            var content = contentParam.Data;

            if (!IsExistCharactor(session.Group.ID, charactor))
            {
                TryToInsertChar(session, charactor, settingName, content);
            }
            else
            {
                TryToUpdateChar(session, charactor, settingName, content);
            }

            return true;
        }

        private static void TryToInsertChar(InboxSession session, string charactor, string settingName, string content)
        {
            if (IsUserFullChar(session))
            {
                session.SendBack($"每个用户只能设定{MaxCharNumPerUser}个人物哦~");
            }
            else
            {
                InsertSetting(session, charactor, settingName, content);
            }
        }

        private static void TryToUpdateChar(InboxSession session, string charactor, string settingName, string content)
        {
            if (!IsCharactorCreator(session, charactor))
            {
                session.SendBack("只能修改自己创建的人物哦~");
                return;
            }

            if (IsSettingFull(session.Group.ID, charactor, settingName))
            {
                session.SendBack($"每个人物只能设定{MaxSettingPerChar}个属性哦~");
                return;
            }

            if (IsSettingExist(session.Group.ID, charactor, settingName))
            {
                ModifySetting(session, charactor, settingName, content);
            }
            else
            {
                InsertSetting(session, charactor, settingName, content);
            }
        }

        private static bool IsCharactorCreator(InboxSession session, string charactor)
        {
            var query = CharactorSettingDA.GetByGroupCharactor(session.Group.ID, charactor);
            return query.FirstOrDefault()?.Creator == session.User.ID;
        }

        private static bool IsSettingExist(string fromGroup, string charactor, string settingName)
        {
            var query = CharactorSettingDA.GetGroupCharactorSetting(fromGroup, charactor, settingName);
            return !query.IsNullOrEmpty();
        }

        private static bool IsUserFullChar(InboxSession session)
        {
            var query = CharactorSettingDA.GetByGroupCreator(session.Group.ID, session.User.ID);
            if (query.IsNullOrEmpty())
            {
                return false;
            }

            query = query.GroupBy(p => p.Charactor).Select(p => p.First()).ToList();
            return !query.IsNullOrEmpty() && query.Count > MaxCharNumPerUser;
        }

        private static bool IsSettingFull(string fromGroup, string charactor, string settingName)
        {
            var query = CharactorSettingDA.GetGroupCharactorNotSetting(fromGroup, charactor, settingName);
            return !query.IsNullOrEmpty() && query.Count > MaxSettingPerChar;
        }

        private static bool IsExistCharactor(string groupNumber, string charactor)
        {
            var query = CharactorSettingDA.GetByGroupCharactor(groupNumber, charactor);
            return !query.IsNullOrEmpty();
        }

        private static void ModifySetting(InboxSession session, string charactor, string settingName, string content)
        {
            var cs = CharactorSettingDA.GetOnly(session.Group.ID,charactor,settingName);
            if (cs != null)
            {
                cs.Content = content;
            }

            cs.Update();
            session.SendBack("修改设定成功！");
        }

        private static void InsertSetting(InboxSession session, string charactor, string settingName, string content)
        {
            var cs = new CharactorSetting
            {
                CreateTime = DateTime.Now,
                GroupID = session.Group.ID,
                Creator = session.User.ID,
                Charactor = charactor,
                SettingName = settingName,
                Content = content
            };
            cs.Insert();

            session.SendBack("设定成功！");
        }

        [ModuleEnter(Command = "删除人物", Description = "删除一个人物", SyntaxHint = "[人物名]", ChannelType = ChannelType.Messaging)]
        public bool DeleteCharactor(InboxSession session, string charactor)
        {
            var query = CharactorSettingDA.GetByGroupCharactor(session.Group.ID, charactor);
            if (query.IsNullOrEmpty())
            {
                session.SendBack("这个人物还没有被创建呢！");
                return false;
            }

            if (query.First().Creator != session.User.ID)
            {
                session.SendBack("你只能删除自己创建的人物噢！");
                return false;
            }

            foreach (var c in query)
            {
                c.Delete();
            }

            session.SendBack("删除成功！");
            return true;
        }

        [ModuleEnter(Command = "人物设定浏览", Description = "浏览一个人物的全部设定", SyntaxHint = "[人物名]", ChannelType = ChannelType.Messaging)]
        public bool ViewCharactor(InboxSession session, string charactor)
        {
            var query = CharactorSettingDA.GetByGroupCharactor(session.Group.ID, charactor);
            if (query.IsNullOrEmpty())
            {
                session.SendBack("这个人物还没有创建哦~");
                return false;
            }

            var buffer = new OutputBuffer(session);
            buffer.Add(charactor + ':');
            buffer.AddPair(query.ToDictionary(c => c.SettingName, c => c.Content));
            buffer.Send();
            return true;
        }
    }
}